//
//  ARP_AlertAppDelegate.m
//  ARP Alert
//
//  Created by James Richardson on 7/28/11.
//  Copyright 2011 Home. All rights reserved.
//

#import "ARP_AlertAppDelegate.h"
#import <Security/Security.h>
#import "messages.h"

@implementation ARP_AlertAppDelegate

@synthesize window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
    NSLog(@"appDidFinishLaunching");
    
    ARParr = [[NSMutableArray alloc] init];
    NETarr = [[NSMutableArray alloc] init];
    TRUSTarr = [[NSMutableArray alloc] init];
    
    [self load];
    [self refreshData];
    [self refreshButtons];
    [self refreshTables];
    [self checkAlertUser];
    
    
    if([autoCheckForUpdate state])
        [self checkForUpdate:NULL];
    
    NSTimer* timer = [NSTimer timerWithTimeInterval:5.0
                                         target:self
                                       selector:@selector(mainLoopTimerRefresh:)
                                       userInfo:nil
                                        repeats:YES];
	
	
	[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
      
}
- (void)applicationWillTerminate:(NSNotification *)notification{
    
    [self save];
}

- (void)awakeFromNib{
    //NSLog(@"awakeFromNib");
}

- (void)load{
    NSLog(@"loading...");
    
    // Get current version ("Bundle Version") from the default Info.plist file
    NSString *currentVersion = (NSString*)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
    NSArray *prevStartupVersions = [[NSUserDefaults standardUserDefaults] arrayForKey:@"prevStartupVersions"];
    if (prevStartupVersions == nil) 
    {
        // Starting up for first time with NO pre-existing installs (e.g., fresh 
        // install of some version)
        //[self firstStartAfterFreshInstall];
        
        NSAlert *newRun = [NSAlert alertWithMessageText:MSG_NEWRUN_SMALL defaultButton:MSG_OK alternateButton:MSG_CANCEL otherButton:nil informativeTextWithFormat:MSG_NEWRUN];
        
        [newRun runModal];
        
        
        [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:currentVersion] forKey:@"prevStartupVersions"];
    }
    else
    {
        if (![prevStartupVersions containsObject:currentVersion]) 
        {
            // Starting up for first time with this version of the app. This
            // means a different version of the app was alread installed once 
            // and started.
            //[self firstStartAfterUpgradeDowngrade];
            NSMutableArray *updatedPrevStartVersions = [NSMutableArray arrayWithArray:prevStartupVersions];
            [updatedPrevStartVersions addObject:currentVersion];
            [[NSUserDefaults standardUserDefaults] setObject:updatedPrevStartVersions forKey:@"prevStartupVersions"];
            
            NSAlert *newRun = [NSAlert alertWithMessageText:MSG_UPGRADERUN_SMALL defaultButton:MSG_OK alternateButton:MSG_CANCEL otherButton:nil informativeTextWithFormat:MSG_UPGRADERUN];
            
            [newRun runModal];
        }
    }
    
    NSArray* tmp = [[NSUserDefaults standardUserDefaults] arrayForKey:@"savedMACs"];
	
	for(int t=0;t<[tmp count];t++)
		[TRUSTarr addObject:[tmp objectAtIndex:t]];
    
    if([[NSUserDefaults standardUserDefaults] boolForKey:@"AutoCheckForUpdates"])
        [autoCheckForUpdate setState:1];
    else
        [autoCheckForUpdate setState:0];
    
    // Save changes to disk
    [[NSUserDefaults standardUserDefaults] synchronize];

}



- (void)save{
    NSLog(@"saving...");
    
    NSArray* tmp = [[NSArray alloc] initWithArray:TRUSTarr];
    
    [[NSUserDefaults standardUserDefaults] setObject:tmp forKey:@"savedMACs"];
    
    if([autoCheckForUpdate state])
        [[NSUserDefaults standardUserDefaults] setObject:@"1" forKey:@"AutoCheckForUpdates"];
    else
        [[NSUserDefaults standardUserDefaults] setObject:@"0" forKey:@"AutoCheckForUpdates"];
    
    [[NSUserDefaults standardUserDefaults] synchronize];
}

- (IBAction)checkForUpdate:(id)sender
// check for online updates
{
    NSString *currAppName = MSG_APPNAME; // the name of this app
    NSString *currVersionNumber = MSG_VERSION; // the version of this app
    
    // get the version info from the web
    NSDictionary *productVersionDict = [NSDictionary dictionaryWithContentsOfURL:
                                        [NSURL URLWithString:VERSION_CHECK_URL]];
    NSString *latestVersionNumber = [productVersionDict valueForKey:VERSIONDICTKEY];
    
    if (latestVersionNumber == nil) { // no xml file could be found
        NSBeep();
        NSRunAlertPanel(ALE_NOUPDATECHECK1, ALE_NOUPDATECHECK2, ALE_ILLCHECKLATER, nil, nil);
    } else {
        if([latestVersionNumber isEqualToString: currVersionNumber]) { // software is up to date
            NSRunAlertPanel(ALE_NOUPDATEFOUND1, [NSString stringWithFormat: ALE_NOUPDATEFOUND2, currVersionNumber, currAppName], MSG_OK, nil, nil);
        } else { // tell user to download a new version
            int button = NSRunAlertPanel(ALE_NEWVERSFOUND1, [NSString stringWithFormat: ALE_NEWVERSFOUND2, latestVersionNumber], MSG_YES, MSG_NO, nil);
            if (button == NSOKButton) {
                [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:DOWNLOAD_NEW_URL]];
            }
            
            
        }
    }
}

-(void)mainLoopTimerRefresh:(NSTimer*)ntp{
    [self refreshAll:NULL];
}

-(IBAction)refreshAll:(id)sender{
    [self refreshData];
    [self refreshButtons];
    [self refreshTables];
    [self checkAlertUser];
}

- (void)checkAlertUser{
    //alerts the user if there are no trusted connections on the arp (not in the trust arr)
    
    NSLog(@"CHECKING ALE");
    
    BOOL alreadyALE = 0;
    BOOL found = 0;
    
    for(int i=0;i<[ARParr count]; i++){
        
        NSMutableDictionary *tmp = [ARParr objectAtIndex:i];
        
        //no trusted connections in arr
        if([TRUSTarr count] == 0 && alreadyALE == 0){
            
            NSAlert *ale = [NSAlert alertWithMessageText:ALE_NOTRUSTarrFOUND_SMALL defaultButton:MSG_OK alternateButton:nil otherButton:nil informativeTextWithFormat:ALE_NOTRUSTarrFOUND];
            
            [ale runModal];
            
            alreadyALE = 1;

            
        }else{
        
            //for lop runs only if there are trusted connections in arr (k=0 --> 0!<0)
            //checks to see if atleast one connection in arp is trusted
            for(int k=0;k<[TRUSTarr count];k++){
            
                NSString *mac = [TRUSTarr objectAtIndex:k];
            
                if([[tmp objectForKey:@"MAC"] isEqualToString:mac]){
                
                    found = 1;

                }
            }
                
        }
    }
    
    if(!found){
        NSAlert *ale = [NSAlert alertWithMessageText:ALE_NOTRUSTFOUND_SMALL defaultButton:MSG_OK alternateButton:nil otherButton:nil informativeTextWithFormat:ALE_NOTRUSTFOUND];
        [ale runModal];
    }
}

- (void)staticChecker{
    
    for(int i=0;i<[ARParr count];i++){
        NSMutableDictionary *tmp = [ARParr objectAtIndex:i];
        
        //NSLog(@"STATIC STATUS '%@'",[tmp objectForKey:@"MAC"]);

        
        if([[tmp objectForKey:@"MAC"] isEqualToString:@"permanent"]){
            //NSLog(@"STATIC STATUS %d ****************************************************",ARPisStatic);
            ARPisStatic = 1;
            break;
        }
        else
            ARPisStatic = 0;
        
    }
    
    
}

- (void)refreshButtons{
    
    //table buttons NOT refreshed here
    //they are refreshed in last method
    
    [self staticChecker];
    
    //NSLog(@"STATIC CHECKER: %d",ARPisStatic);
    
    if(ARPisStatic)
        [removeTrustButton setEnabled:0];
    else
        [removeTrustButton setEnabled:1];
    
    if([TRUSTarr count] == 0 && ARPisStatic){
        //arp table is static && nothing in the trust arr
        
        //needs to be true or else user cannot do anything
        [staticButton setEnabled:TRUE];
        [dynamicButton setEnabled:TRUE];
        
        [radioButtons selectCellWithTag:0];
        //[staticButton setState:NSOnState];
        //[staticButton setNextState];
        
        //[dynamicButton setState:NSOffState];
        //[dynamicButton setNextState];
    }else
        if([TRUSTarr count] == 0 && !ARPisStatic){
            //arp table is not static && nothing in the trust arr
            
            [staticButton setEnabled:FALSE];
            [dynamicButton setEnabled:FALSE];
            
            [radioButtons selectCellWithTag:1];
            
            //[staticButton setState:NSOffState];
            //[staticButton setNextState];
            
            //[dynamicButton setState:NSOnState];
            //[dynamicButton setNextState];
        }
        else
            if([TRUSTarr count] != 0 && ARPisStatic){
                //arp table is static && stuff in the trust arr
                
                [staticButton setEnabled:TRUE];
                [dynamicButton setEnabled:TRUE];
                
                [radioButtons selectCellWithTag:0];
                
                //[staticButton setState:NSOnState];
                //[staticButton setNextState];
                
                //[dynamicButton setState:NSOffState];
                //[dynamicButton setNextState];
            }
            else
            {
                //arp table is not static && stuff in trust arr
                
                [staticButton setEnabled:TRUE];
                [dynamicButton setEnabled:TRUE];
                
                [radioButtons selectCellWithTag:1];
                
                //[staticButton setState:NSOffState];
                //[staticButton setNextState];
                
                //[dynamicButton setState:NSOnState];
                //[dynamicButton setNextState];
            }

}

- (void)refreshTables{
    [ARPTableView reloadData];
    [NETTableView reloadData];
    [TRUSTTableView reloadData];     
}

-(IBAction)radioGroupDynamic:(id)sender{
    
    //NSButtonCell *selCell = [sender selectedCell];
    //NSLog(@"Selected cell is %ld", [selCell tag]);
    NSLog(@"STATIC --> DYNAMIC");
    
    char *tool = "/usr/sbin/arp";
    char *args[] = {"-d", "-a", NULL};
    
    int ret = auth(tool,args);
    
    if(ret != 1){
        //[radioButtons selectCellWithTag:0];
    }
    
    //NSLog(@"RETURN: %d",ret);
    
    
    [self refreshAll:NULL];
}

-(IBAction)radioGroupStatic:(id)sender{
    
    //NSButtonCell *selCell = [sender selectedCell];
    
    //NSLog(@"Selected cell is %ld", [selCell tag]);
    
    NSLog(@"DYNAMIC --> STATIC");
    
    if([self writeToFile]){
        
        char *tool = "/usr/sbin/arp";
        char *args[] = {"-f", "/tmp/arpS.txt", NULL};
        
        int ret = auth(tool,args);
        
        if(ret != 1){
            //[radioButtons selectCellWithTag:1];
            //[self refreshTables];
            
        }
        
        //NSLog(@"RETURN: %d",ret);
    }
    else{
        NSLog(@"Failed to write arp static file --> File save unsucessful OR no data in trust arr");
        
        //[radioButtons selectCellWithTag:1];
        
        //[self refreshTables];
        
        //[dynamicButton setState:TRUE];
        //[dynamicButton setNextState];
        //[staticButton setState:FALSE];
        //[staticButton setNextState];  
    }
    
    [self refreshAll:NULL];
}
//
int auth(char *tool, char *args[]){
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
    int res = 0;
	
    OSStatus status;  // http://developer.apple.com/documentation/Security/Reference/authorization_ref/Reference/reference.html#//apple_ref/doc/uid/TP30000826-CH4g-CJBEABHG
    AuthorizationRef authorizationRef;
	
    // AuthorizationCreate and pass NULL as the initial AuthorizationRights set so that the AuthorizationRef
    // gets created successfully, and then later call AuthorizationCopyRights to determine or extend the allowable rights.
    // http://developer.apple.com/qa/qa2001/qa1172.html
    status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef);
    if (status != errAuthorizationSuccess)
        NSLog(@"Error Creating Initial Authorization: %d", status);
	
    // kAuthorizationRightExecute == "system.privilege.admin"
    AuthorizationItem right = {kAuthorizationRightExecute, 0, NULL, 0};
    AuthorizationRights rights = {1, &right};
    AuthorizationFlags flags = kAuthorizationFlagDefaults |
	kAuthorizationFlagInteractionAllowed |
	kAuthorizationFlagPreAuthorize |
	kAuthorizationFlagExtendRights;
	
    // Call AuthorizationCopyRights to determine or extend the allowable rights.
    status = AuthorizationCopyRights(authorizationRef, &rights, NULL, flags, NULL);
    if (status != errAuthorizationSuccess)
        NSLog(@"Copy Rights Unsuccessful: %d", status);
	
    // EXAMPLE 1: This system tool should work as intended. NOTE: The
    // do-while was used to create scope rather than a function to
    // make this demonstration code read more top-down.
    do {
        //NSLog(@"\n\n** %@ **\n\n", @"This command should work.");
        //char *tool = "/sbin/dmesg";
        //char *args[] = {NULL};
        
        
        FILE *pipe = NULL;
		
        status = AuthorizationExecuteWithPrivileges(authorizationRef, tool, kAuthorizationFlagDefaults, args, &pipe);
        if (status != errAuthorizationSuccess)
            NSLog(@"Error: %d", status);
		
        char readBuffer[128];
        if (status == errAuthorizationSuccess) {
            
            res = 1;
            
            for (;;) {
                int bytesRead = read(fileno(pipe), readBuffer, sizeof(readBuffer));
                if (bytesRead < 1) break;
                write(fileno(stdout), readBuffer, bytesRead);
            }
        }
    } while (0);
	
    // The only way to guarantee that a credential acquired when you request a right
    // is not shared with other authorization instances is to destroy the credential.
    // To do so, call the AuthorizationFree function with the flag kAuthorizationFlagDestroyRights.
    // http://developer.apple.com/documentation/Security/Conceptual/authorization_concepts/02authconcepts/chapter_2_section_7.html
    status = AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights);
	
    [pool release];
    
    return res;
}



-(BOOL)writeToFile{
    
    BOOL res = false;
    
    int hits = 0;
    
    for(int i=0;i<[TRUSTarr count]; i++){
        for(int k=0;k<[ARParr count]; k++){
            
            NSMutableDictionary *arp = [ARParr objectAtIndex:k];
            
            if([[arp objectForKey:@"MAC"] isEqualToString:[TRUSTarr objectAtIndex:i]]){
                
                
                if(hits == 0){
                    NSMutableString* tmp = [NSString stringWithFormat:@"%s %s \n",[[arp objectForKey:@"IP"] UTF8String],[[TRUSTarr objectAtIndex:i] UTF8String]];
                    
                    [tmp writeToFile:@"/tmp/arpS.txt" atomically:1];
                }
                else{
                    NSMutableString* tmp2 = [[NSMutableString alloc] initWithContentsOfFile:@"/tmp/arpS.txt"];
                    
                    [tmp2 appendString:[NSString stringWithFormat:@"%s %s \n",[[arp objectForKey:@"IP"] UTF8String],[[TRUSTarr objectAtIndex:i] UTF8String]]];
                    
                    [tmp2 writeToFile:@"/tmp/arpS.txt" atomically:1];
                    
                    [tmp2 release];
                    
                }
                
                res = true;
                
                hits++;
            }
        }
        
    }
    
    return res;
    
}

/*-(IBAction)populateDict:(id)sender{
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];
    
    [ARParr removeAllObjects];
    [NETarr removeAllObjects];
    
    GETnetworkInfo *infoMaker = [[[GETnetworkInfo alloc] init] autorelease];
    
    [infoMaker populateARP:ARParr];
    [infoMaker populateNET:NETarr];
    
    for(int i=0;i<[ARParr count]; i++){
        if([self checkForTrust_location:i]){
            NSMutableDictionary *tmp = [ARParr objectAtIndex:i];
            [tmp setObject:@"1" forKey:@"Trust"];
        }
    }
    
    [self refreshTables];
    
    [pool release];
}*/

- (void)refreshData {
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];
    
    [ARParr removeAllObjects];
    [NETarr removeAllObjects];
    
    GETnetworkInfo *infoMaker = [[[GETnetworkInfo alloc] init] autorelease];
    
    [infoMaker populateARP:ARParr];
    [infoMaker populateNET:NETarr];
    
    for(int i=0;i<[ARParr count]; i++){
        if([self checkForTrust_location:i]){
            NSMutableDictionary *tmp = [ARParr objectAtIndex:i];
            [tmp setObject:@"1" forKey:@"Trust"];
        }
    }
    
    [self refreshTables];
    
    [pool release];
}



-(IBAction)removeTrust:(id)sender{
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];
    
    NSInteger row = [TRUSTTableView selectedRow];
    
    if(row != -1 || !(row>[TRUSTarr count]))
        [TRUSTarr removeObjectAtIndex:row]; //***********************************************************************************
    
    //[self refreshTables];
    
    [self refreshAll:NULL];
    
    [pool release];
}

-(BOOL)checkForTrust_location:(NSInteger)arrayLocation{
    
    NSMutableDictionary *tmp = [ARParr objectAtIndex:arrayLocation];
    
    NSString *mac = [tmp objectForKey:@"MAC"];
    
    //[[tmp objectForKey:@"Trust"] isEqualToString:@"1"] &&
    if( [self checkForTrust_deep:mac])
        return true;
    else
        return false;
   
}
-(BOOL)checkForTrust_deep:(NSString*)mac{
    
    for(int k=0; k<[TRUSTarr count]; k++){
        
        if([[TRUSTarr objectAtIndex:k] isEqualToString:mac])
            return true;
        
    }
    return false;
}


- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {

    if(tableView == ARPTableView)
        return [ARParr count];
    else
    if(tableView == NETTableView)
        return [NETarr count];
    else
    if(tableView == TRUSTTableView)
        return [TRUSTarr count];
    else
        return 0;
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    
    if(tableView  == ARPTableView && [ARParr count] != 0){
        
        NSMutableDictionary *tmp = [ARParr objectAtIndex:row];
        
        if(tableColumn == ARP_ipCol)				
            return [tmp objectForKey:@"IP"];
        if(tableColumn == ARP_macCol)
            return [tmp objectForKey:@"MAC"];
        if(tableColumn == ARP_hostCol)
            return [tmp objectForKey:@"Host"];
        if(tableColumn == ARP_trustCol)
            return [NSNumber numberWithInteger:([self checkForTrust_location:row] ? NSOnState : NSOffState)];
        
    }
    else
    if(tableView == NETTableView && [NETarr count] != 0){
        
        NSMutableDictionary *tmp = [NETarr objectAtIndex:row];
        
        if(tableColumn == NET_ipCol)
            return [tmp objectForKey:@"IP"];
        if(tableColumn == NET_macCol)
            return [tmp objectForKey:@"MAC"];
        if(tableColumn == NET_interfaceCol)
            return [tmp objectForKey:@"Interface"];
        
    }
    else
    if(tableView == TRUSTTableView && tableColumn == TRUST_macCol)
        return [TRUSTarr objectAtIndex:row];
    
    
    return 0;
}


- (void)tableView:(NSTableView *)tableView setObjectValue:(id)value forTableColumn:(NSTableColumn *)column row:(NSInteger)row {          
    
    if(tableView  == ARPTableView && [ARParr count] != 0 && column == ARP_trustCol){
        NSMutableDictionary *tmp = [ARParr objectAtIndex:row];
        
        if(![self checkForTrust_location:row]){
            
                        
            //we do not currently trust the connection --> now we want to
            [tmp setObject:@"1" forKey:@"Trust"];
            NSString *mac = [tmp objectForKey:@"MAC"] ;
            
            //NSLog(@"ADDING TRUSTED CONNECTION: %@",mac);
            
            [TRUSTarr addObject:mac];
            
        }
        else{
            
            
            
            //un-trust the conenction ... distrust ... whatever
            [tmp setObject:@"0" forKey:@"Trust"];
            
            NSString *mac = [tmp objectForKey:@"MAC"];
            
            //NSLog(@"REMOVING TRUSTED CONNECTION: %@",mac);
            
            if([self checkForTrust_deep:mac])
                for(int i = 0; i<[TRUSTarr count]; i++){
                    
                    NSString *macCMP = [TRUSTarr objectAtIndex:i];
                    
                    if([mac isEqualToString:macCMP]){
                        [TRUSTarr removeObjectAtIndex:i];
                        break;
                    }
                        //[TRUSTarr removeObjectAtIndex:i]; *****************************************************************************
                }
        }
        //[TRUSTTableView reloadData];
        
    }
    

    
} 
- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell
   forTableColumn:(NSTableColumn *)column row:(int)row{
    
    if(ARPisStatic && column == ARP_trustCol){
        [cell setEnabled:0];
        
        //DO NOT USE [self refreshAll]; IN TABLE METHODS (B/C LOOP)
        [TRUSTTableView reloadData];
        [self refreshButtons];
    }
    else{
        [cell setEnabled:1];
        
        //DO NOT USE [self refreshAll] IN TABLE METHODS (B/C LOOP)
        [TRUSTTableView reloadData];
        [self refreshButtons];
    }
    
    //[self refreshTables];
}
    

@end
